package org.montsuqi.util; import java.awt.*; import java.awt.print.*; import java.nio.channels.FileChannel; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.io.File; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFPage; import com.sun.pdfview.PDFRenderer; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import javax.print.DocFlavor; import javax.print.PrintService; import javax.print.PrintServiceLookup; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.standard.MediaSizeName; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.montsuqi.util.PDFPrint.PDFPrintPage; public class PDFPrint extends Thread { private final File file; private final PrintService printService; private static final Logger logger = LogManager.getLogger(PDFPrint.class); public PDFPrint(File file) { this.file = file; this.printService = null; } public PDFPrint(File file, PrintService printService) { this.file = file; this.printService = printService; } private void print(PDFFile pdfFile, PrintService printService) { HashMap<MediaSizeName, ArrayList<PDFPage>> map = new HashMap<>(); for (int i = 0; i < pdfFile.getNumPages(); i++) { PDFPage page = pdfFile.getPage(i + 1); MediaSizeName mediaSizeName = PDFPaperSize.getPDFPaperSize(page); ArrayList<PDFPage> list = map.get(mediaSizeName); if (list != null) { list.add(page); } else { ArrayList<PDFPage> newList = new ArrayList<>(); newList.add(page); map.put(mediaSizeName, newList); } } for (Map.Entry<MediaSizeName, ArrayList<PDFPage>> e : map.entrySet()) { try { ArrayList<PDFPage> list = e.getValue(); PDFPage[] pages = new PDFPage[list.size()]; for (int i = 0; i < list.size(); i++) { pages[i] = list.get(i); } PDFPrintPage printPage = new PDFPrintPage(pages); MediaSizeName mediaSizeName = e.getKey(); PrintRequestAttributeSet reqset = new HashPrintRequestAttributeSet(); PrinterJob pjob = PrinterJob.getPrinterJob(); pjob.setJobName(file.getName()); pjob.setPrintService(printService); if (mediaSizeName != MediaSizeName.A) { reqset.add(mediaSizeName); } PageFormat pf = pjob.getPageFormat(reqset); Paper paper = pf.getPaper(); paper.setImageableArea(0, 0, paper.getWidth(), paper.getHeight()); pf.setPaper(paper); Book book = new Book(); book.append(printPage, pf, pages.length); pjob.setPageable(book); pjob.print(reqset); } catch (PrinterException ex) { logger.catching(Level.WARN, ex); } } } private void print(PDFFile pdfFile) { PDFPage[] pages = new PDFPage[pdfFile.getNumPages() + 1]; for (int i = 0; i < pdfFile.getNumPages(); i++) { pages[i] = pdfFile.getPage(i + 1); } PDFPrintPage printPage = new PDFPrintPage(pages); PrinterJob pjob = PrinterJob.getPrinterJob(); pjob.setJobName(file.getName()); PrintRequestAttributeSet reqset = new HashPrintRequestAttributeSet(); if (!pjob.printDialog(reqset)) { return; } PageFormat pf = pjob.getPageFormat(reqset); Paper paper = pf.getPaper(); paper.setImageableArea(0, 0, paper.getWidth(), paper.getHeight()); pf.setPaper(paper); Book book = new Book(); book.append(printPage, pf, pdfFile.getNumPages()); pjob.setPageable(book); try { pjob.print(reqset); } catch (PrinterException ex) { logger.catching(Level.WARN, ex); } } @Override public void run() { logger.info("print start - " + file); try { FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel(); ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); PDFFile pdfFile = new PDFFile(bb); // Create PDF Print Page if (printService != null) { print(pdfFile, printService); } else { print(pdfFile); } } catch (java.io.IOException ex) { logger.catching(Level.WARN, ex); } logger.info("print end - " + file); } public static void main(String args[]) throws Exception { DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE; PrintService[] pss = PrintServiceLookup.lookupPrintServices(flavor, null); PrintService ps = null; System.out.println("---- print service"); for (PrintService _ps : pss) { System.out.println(_ps.getName()); if (_ps.getName().equals(args[0])) { ps = _ps; } } for (int i = 0; i < 1; i++) { if (ps == null) { PDFPrint printer = new PDFPrint(new File(args[1])); printer.start(); } else { PDFPrint printer = new PDFPrint(new File(args[1]), ps); printer.start(); } System.out.println(i); Thread.sleep(2000); } } public static class PDFPrintPage implements Printable { /** * The PDFFile to be printed */ private final PDFPage[] pages; /** * Create a new PDFPrintPage object for a particular PDFFile. * * @param _pages */ public PDFPrintPage(PDFPage[] _pages) { pages = _pages; } // from Printable interface: prints a single page, given a Graphics // to draw into, the page format, and the page number. @Override public int print(Graphics g, PageFormat format, int index) throws PrinterException { Graphics2D g2 = (Graphics2D) g; Rectangle2D.Double pageable; double hmargin = GetPrintOption("monsia.util.PDFPrint.hmargin"); double vmargin = GetPrintOption("monsia.util.PDFPrint.vmargin"); double hoffset = GetPrintOption("monsia.util.PDFPrint.hoffset"); double voffset = GetPrintOption("monsia.util.PDFPrint.voffset"); double hratio = 1.0; double vratio = 1.0; double scale; if (hmargin != 0.0) { hratio = hmargin / format.getImageableWidth(); } if (vmargin != 0.0) { vratio = vmargin / format.getImageableHeight(); } if (hratio != 1.0 || vratio != 1.0) { if (hratio < vratio) { vmargin = hratio * format.getImageableHeight(); } else { hmargin = vratio * format.getImageableWidth(); } } scale = (format.getImageableWidth() - hmargin * 2) / format.getImageableWidth() * 1.0; hoffset += hmargin; voffset += vmargin; pageable = new Rectangle2D.Double(hoffset, voffset, format.getImageableWidth() - hmargin * 2, format.getImageableHeight() - vmargin * 2); if (System.getProperty("monsia.util.PDFPrint.debug") != null) { System.out.println("PageFormat.orientation(land:" + PageFormat.LANDSCAPE + ",port:" + PageFormat.PORTRAIT + "):" + format.getOrientation()); System.out.println("PageFormat Imageable:[" + format.getImageableX() + "," + format.getImageableY() + "],[" + format.getImageableWidth() + "," + format.getImageableHeight() + "]"); g2.setColor(Color.BLACK); float dash[] = {1.0f}; BasicStroke dashStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, dash, 0.0f); g2.setStroke(dashStroke); g2.setStroke(new BasicStroke(0.1f)); int mm = 10; for (int i = 0; i < 100; i++) { int p = (int) Math.floor((i * PDFPrint.MMto72DPI(mm))); g2.drawLine(p, 0, p, 2000); g2.drawLine(0, p, 2000, p); } System.out.println("pageable:" + pageable); g2.setStroke(new BasicStroke(2.0f)); g2.drawRect((int) pageable.x, (int) pageable.y, (int) pageable.width, (int) pageable.height); } if (index < 0 || index >= pages.length) { logger.warn("no such page index:" + index + " pages.length:" + pages.length); return NO_SUCH_PAGE; } // fit the PDFPage into the printing area PDFPage page = pages[index]; int width = (int) page.getWidth(); int height = (int) page.getHeight(); if (format.getOrientation() == PageFormat.PORTRAIT) { if (height > width) { g2.transform(new AffineTransform(scale, 0f, 0f, scale, hoffset, voffset)); } else { g2.transform(new AffineTransform(0f, -1.0 * scale, scale, 0f, voffset, -hoffset + width)); } } else if (format.getOrientation() == PageFormat.LANDSCAPE) { if (width > height) { g2.transform(new AffineTransform(scale, 0f, 0f, scale, hoffset, voffset)); } else { g2.transform(new AffineTransform(0f, scale, -1.0 * scale, 0f, -voffset + height, hoffset)); } } if (System.getProperty("monsia.util.PDFPrint.debug") != null) { System.out.println("scale:" + scale); } // render the page PDFRenderer pgs = new PDFRenderer(page, g2, new Rectangle(0, 0, width, height), null, null); try { page.waitForFinish(); pgs.run(); } catch (InterruptedException ie) { logger.catching(Level.WARN, ie); } return PAGE_EXISTS; } } private static double MMto72DPI(double mm) { if (mm == 0.0) { return 0.0; } return (mm / 25.4) * 72.0; } private static double GetPrintOption(String property) { double _72dpi = 0.0; if (System.getProperty(property) != null) { double mm = Double.valueOf(System.getProperty(property)); _72dpi = PDFPrint.MMto72DPI(mm); if (System.getProperty("monsia.util.PDFPrint.debug") != null) { System.out.println(property + ":" + mm + "(mm) " + _72dpi + "(72dpi)"); } } return _72dpi; } }